use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use lru::LruCache;
use crate::{crypto::CryptoService, trust_network_client::TrustNetworkClient, trust_tree::{TrustCertificate, TrustTree}};

#[derive(Serialize, Deserialize, Clone)]
pub struct TrustChainValidation {
    pub target_peer_id: String,
    pub chain_length: usize,
    pub is_valid: bool,
    pub trust_level: u8,
    pub validation_timestamp: u64,
}

impl TrustChainValidation {
    pub fn invalid() -> Self {
        Self {
            target_peer_id: "".to_string(),
            chain_length: 0,
            is_valid: false,
            trust_level: 0,
            validation_timestamp: current_timestamp(),
        }
    }
}

pub struct DistributedTrustSystem {
    trust_tree: TrustTree,
    local_peer_id: String,
    local_certificate: Option<TrustCertificate>,
    certificate_cache: LruCache<String, TrustCertificate>,
    network_client: TrustNetworkClient,
}

impl DistributedTrustSystem {
    pub fn new(local_peer_id: String) -> Self {
        let trust_tree = TrustTree::new(7, 7);
        
        Self {
            trust_tree,
            local_peer_id,
            local_certificate: None,
            certificate_cache: LruCache::new(1000),
            network_client: TrustNetworkClient::new(),
        }
    }

    pub async fn validate_trust_chain(
        &mut self,
        target_peer_id: &str,
    ) -> Result<TrustChainValidation, String> {
        if let Some(cert) = self.get_local_certificate(target_peer_id) {
            return self.validate_local_certificate_chain(cert).await;
        }

        if let Some(cached_cert) = self.certificate_cache.get(target_peer_id) {
            return self.validate_certificate_chain(cached_cert).await;
        }

        let certificate = self.network_client
            .get_certificate(target_peer_id)
            .await
            .map_err(|e| format!("Failed to fetch certificate: {}", e))?;

        let validation = self.validate_certificate_chain(&certificate).await?;
        self.certificate_cache.put(target_peer_id.to_string(), certificate);

        Ok(validation)
    }

    async fn validate_certificate_chain(
        &mut self,
        certificate: &TrustCertificate,
    ) -> Result<TrustChainValidation, String> {
        let mut current_cert = certificate.clone();
        let mut chain = Vec::new();
        let mut visited = HashSet::new();

        loop {
            if visited.contains(&current_cert.peer_id) {
                return Err("Certificate chain contains a loop".to_string());
            }
            visited.insert(current_cert.peer_id.clone());

            if current_timestamp() > current_cert.expiry_date {
                return Err("Certificate has expired".to_string());
            }

            if !current_cert.is_active {
                return Err("Certificate is not active".to_string());
            }

            chain.push(current_cert.clone());

            if self.trust_tree.is_god_peer(&current_cert.peer_id) {
                break;
            }

            let parent_cert = self.get_parent_certificate(&current_cert).await?;
            current_cert = parent_cert;
        }

        if chain.last().map(|c| !self.trust_tree.is_god_peer(&c.peer_id)).unwrap_or(true) {
            return Err("Trust chain does not reach God Peer".to_string());
        }

        Ok(TrustChainValidation {
            target_peer_id: certificate.peer_id.clone(),
            chain_length: chain.len(),
            is_valid: true,
            trust_level: certificate.trust_level,
            validation_timestamp: current_timestamp(),
        })
    }

    async fn get_parent_certificate(
        &mut self,
        certificate: &TrustCertificate,
    ) -> Result<TrustCertificate, String> {
        let parent_id = &certificate.parent_peer_id;

        if let Some(cert) = self.get_local_certificate(parent_id) {
            return Ok(cert);
        }

        if let Some(cached) = self.certificate_cache.get(parent_id) {
            return Ok(cached.clone());
        }

        let parent_cert = self.network_client
            .get_certificate(parent_id)
            .await
            .map_err(|e| format!("Failed to fetch parent certificate: {}", e))?;

        self.certificate_cache.put(parent_id.to_string(), parent_cert.clone());
        Ok(parent_cert)
    }

    fn get_local_certificate(&self, peer_id: &str) -> Option<TrustCertificate> {
        if self.trust_tree.is_god_peer(peer_id) {
            return self.trust_tree.get_certificate(peer_id).cloned();
        }

        if let Some(local_cert) = &self.local_certificate {
            if local_cert.peer_id == peer_id {
                return Some(local_cert.clone());
            }
        }

        None
    }

    async fn validate_local_certificate_chain(
        &self,
        certificate: TrustCertificate,
    ) -> Result<TrustChainValidation, String> {
        // 简化验证：假设上级证书已经过验证
        Ok(TrustChainValidation {
            target_peer_id: certificate.peer_id,
            chain_length: certificate.trust_level as usize + 1,
            is_valid: true,
            trust_level: certificate.trust_level,
            validation_timestamp: current_timestamp(),
        })
    }

    pub fn initialize_network(&mut self) -> Result<(), String> {
        // 验证God Peer存在
        let god_cert = self.trust_tree.get_certificate(crate::trust_tree::GOD_PEER_ID)
            .ok_or("God Peer certificate not found")?;

        println!("Trust network initialized with God Peer: {}", crate::trust_tree::GOD_PEER_ID);
        Ok(())
    }

    pub fn cleanup_expired_cache(&mut self) {
        let current_time = current_timestamp();
        let expired_keys: Vec<String> = self.certificate_cache.iter()
            .filter(|(_, cert)| current_time > cert.expiry_date)
            .map(|(key, _)| key.clone())
            .collect();

        for key in expired_keys {
            self.certificate_cache.pop(&key);
        }
    }
}

fn current_timestamp() -> u64 {
    use std::time::{SystemTime, UNIX_EPOCH};
    SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()
}